﻿function ConvertTo-ManagementServerObject
{
    [cmdletbinding(DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PsObject]$ManifestServerObject
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start ConvertTo-ManagementServerObject for $($ManifestServerObject.UniqueKey) identified by $($ManifestServerObject.HostName)"
    }
    End
    {
        write-verbose "End ConvertTo-ManagementServerObject for $($ManifestServerObject.UniqueKey) identified by $($ManifestServerObject.HostName)"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process
    {
        $ManagementServerObject = New-Object PsObject
        <#
         -Property @{UniqueKey=$ManifestServerObject.UniqueKey
                                                                  HostName=$ManifestServerObject.HostName
                                                                 }
        #>
        
        #Copy all properties from source Object to TargetObject
        $ManifestServerObject | Get-Member -MemberType NoteProperty |  ? {($_.Definition -notlike 'System.Management.Automation.PSCustomObject*') `
                                                                     -and ($_.Definition -notlike '*Collection*') `
                                                                     -and ($_.Definition -notlike '*Object*')} | ForEach-Object {

            $value = Get-Value -Object $ManifestServerObject -Value $($ManifestServerObject.$($_.Name))
            $ManagementServerObject | Add-Member -MemberType NoteProperty -Name $_.Name -Value $value
        }
        write-debug "ConvertTo-ManagementServerObject - ManifestServerObject direct attributes : $ManagementServerObject"

        #Create Servers Folders
        $ManifestServerObject.Folders | ? {$_.Level -eq 'Server'} | ForEach-Object {
            
            write-debug "ConvertTo-ManagementServerObject - Folders : $_"
            $propertyName = $_.UniqueKey
            switch($propertyName)
            {
                "RootDeliveryDirectory" {$propertyName="DeliveryFolder"}
                "RootBackupDirectory" {$propertyName="BackupFolder"}
                "RootWorkingDirectory" {$propertyName="WorkdirFolder"}
                
            }
            
            
            
            $ManagementServerObject | Add-Member -MemberType NoteProperty -Name $propertyName -Value (get-fullpath $_)
            if ($_.Share)
            {
                Write-Verbose "Detect share '$($_.Share)' on folder '$($_.uniqueKey)', Add Remote To uniqueKey"
                $remoteSharePropertyName = "Remote$propertyName"
                $remoteSharePropertyValue = [System.IO.Path]::Combine("\\$($ManifestServerObject.HostName)",$_.Share)
                $ManagementServerObject | Add-Member -MemberType NoteProperty -Name $remoteSharePropertyName -Value $remoteSharePropertyValue

            }

        }
        write-debug "ConvertTo-ManagementServerObject - ManifestServerObject with folders : $ManagementServerObject"

        #Check mandatories folders 
        if ((-not $ManagementServerObject.DeliveryFolder) -or (-not $ManagementServerObject.BackupFolder) -or (-not $ManagementServerObject.WorkdirFolder))
        {
            throw New-Object System.Exception "DeliveryFolder, BackupFolder, WorkdirFolder is mandatory to using Applicatopn.Management Module"
        }


        #Check Winrm connections options
        if (-not $ManagementServerObject.WinrmUseSSL) 
        {
            Write-Warning "Winrm option for SSL is not specified, set False by default for server '$($_.HostName)'"
            $ManagementServerObject | Add-Member -MemberType NoteProperty -Name WinrmUseSSL -Value $false -Force
        }

        if (-not $ManagementServerObject.WinrmPort) 
        {
            Write-Warning "Winrm option for listen port is not specified, set 5985 by default for server '$($_.HostName)'"
            $ManagementServerObject | Add-Member -MemberType NoteProperty -Name WinrmPort -Value 5985 -Force
        }

        #Add property for management module
        if (-not $ManagementServerObject.ApplicationManagementModule) 
        {
            $ManagementServerObject | Add-Member -MemberType NoteProperty -Name ApplicationManagementModule -Value $null
        }


        #Add deployment Target information
        $deploymentTarget = Get-DeploymentTarget -CurrentObject $ManifestServerObject


         $deploymentTarget | Get-Member -MemberType NoteProperty |  ? {($_.Definition -notlike 'System.Management.Automation.PSCustomObject*') `
                                                                     -and ($_.Definition -notlike '*Collection*') `
                                                                     -and ($_.Definition -notlike '*Object*') `
                                                                     -and ($_.Name -notin 'ElementType','Level','UniqueKey')} | ForEach-Object {
            
            Write-Debug "Member : $($_)"
            $ManagementServerObject | Add-Member -MemberType NoteProperty -Name $_.Name -Value (Get-Value -Object $deploymentTarget -Value  $deploymentTarget.$($_.Name))
        }

        #Add Components collection to be ready to store all components
        $components = @()
        $ManagementServerObject | Add-Member -MemberType NoteProperty -Name Components -Value $components

        #Browse components at execution container level
        foreach($middleware in $ManifestServerObject.Middlewares.Values)
        {
            $middleware.ExecutionContainers.Values | ConvertTo-ManagementComponentObject | ForEach-Object {$ManagementServerObject.Components += $_}
        }

        foreach($component in $ManifestServerObject.Components)
        {
            $component | ConvertTo-ManagementComponentObject | ForEach-Object {$ManagementServerObject.Components += $_}
        }

        #TODO : It's not a correct implementation
        foreach($product in $ManifestServerObject.Products)
        {
            if ($product.Level -ne $null)
            {
                $product | ConvertTo-ManagementComponentObject | ForEach-Object {$ManagementServerObject.Components += $_}
            }
        }



        Write-Output $ManagementServerObject
                                                                    
    }
}


function ConvertTo-ManagementComponentObject
{
    [cmdletbinding(DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [PsObject]$ManifestManagementObject
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start ConvertTo-ManagementComponentObject for type '$($ManifestManagementObject.ElemntType)' identified by '$($ManifestManagementObject.UniqueKey)'"
    }
    End
    {
        write-verbose "End ConvertTo-ManagementComponentObject for type '$($ManifestManagementObject.ElemntType)' identified by '$($ManifestManagementObject.UniqueKey)'"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process
    {
        $ManagementComponentObject = New-Object PsObject

        #Copy all properties from source Object to TargetObject
        $ManifestManagementObject | Get-Member -MemberType NoteProperty |  ? {($_.Definition -notlike 'System.Management.Automation.PSCustomObject*') `
                                                                         -and ($_.Definition -notlike '*Collection*') `
                                                                         -and ($_.Definition -notlike '*Object*')} | ForEach-Object {

            $value = Get-Value -Object $ManifestManagementObject -Value $($ManifestManagementObject.$($_.Name))
            $ManagementComponentObject | Add-Member -MemberType NoteProperty -Name $_.Name -Value $value
        }


        #Add Mandatory properties
        if (-not $ManagementComponentObject.ComponentName){$ManagementComponentObject | Add-Member -MemberType NoteProperty -Name ComponentName -Value $_.UniqueKey}
        if (-not $ManagementComponentObject.Name){$ManagementComponentObject | Add-Member -MemberType NoteProperty -Name Name -Value $_.UniqueKey}

        #Create Components Folders
        $ManifestManagementObject.Folders.Values | ForEach-Object {
                        
            $propertyName = $_.UniqueKey
            
            $ManagementComponentObject | Add-Member -MemberType NoteProperty -Name $propertyName -Value (Get-FullPath -Object  $_)
            if ($_.Share)
            {
                Write-Verbose "Detect share '$($_.Share)' on folder '$($_.uniqueKey)', Add Remote To uniqueKey"
                $remoteSharePropertyName = "Remote$propertyName"
                $remoteSharePropertyValue = [System.IO.Path]::Combine("\\$($ManifestServerObject.HostName)",$_.Share)
                $ManagementComponentObject | Add-Member -MemberType NoteProperty -Name $remoteSharePropertyName -Value $remoteSharePropertyValue
            }
        }

        #Check mandatory properties
        if ((-not $ManagementComponentObject.ComponentType) -or (-not $ManagementComponentObject.ComponentName) -or (-not $ManagementComponentObject.InstallationDirectory))
        {
         #   throw New-Object System.Exception "ComponentType, ComponentName, InstallationDirectory is mandatory to using Applicaton.Management Module, don't find on type '$($ManifestManagementObject.ElementType)' identified by '$($ManifestManagementObject.UniqueKey)'"
        }


        Write-Output $ManagementComponentObject
    }
}

Function New-ManifestDeploymentFile
{
        [cmdletbinding(SupportsShouldProcess=$True)]
        Param(       
        [Parameter(Mandatory=$true)] 
        [ValidateScript({Test-Path $_ -PathType Container})] 
        [String] 
        $DestinationPath,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [PSObject] 
        $DeploymentTarget               
        )
 
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start New-DeploymentManifest_v2 from Application Manifest for application '$($DeploymentTarget.ApplicationName)' verion '$($DeploymentTarget.version)' on environment $($DeploymentTarget.Environment)"
    }
    End
    {
        write-verbose "End New-DeploymentManifest_v2 from Application Manifest for application '$($DeploymentTarget.ApplicationName)' verion '$($DeploymentTarget.version)' on environment $($DeploymentTarget.Environment)"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process 
    {
    
        $ApplicationName = Get-Value -Object $DeploymentTarget -Value $DeploymentTarget.applicationName
        if (-not $ApplicationName) {throw "Unable to find the application name"}

        $destinationFilePath = Join-Path -Path $DestinationPath -ChildPath $ApplicationName
        if ((Test-Path $destinationFilePath -PathType Container) -ne $true)
        {
            New-Item -Path $destinationFilePath -ItemType Container | Out-Null
        }
        
        $destinationFileName = "Deployment_$($DeploymentTarget.Environment).xml"
        $destinationFilePath = Join-Path -Path $destinationFilePath -ChildPath $destinationFileName

            
        if ($PSCmdlet.ShouldProcess("Create deployment manifest $destinationFilePath"))
        {            
            #$DeploymentTarget.Servers.Values | ConvertTo-ManagementServerObject | ConvertTo-Json | Set-Content -Path $destinationFilePath
            $root = New-Object PSObject
            $xmlRoot = [Xml]$root

            $deploymentTargetNode = $xmlRoot.CreateElement($DeploymentTarget.ElementType)
            $outNull = $xmlRoot.AppendChild($deploymentTargetNode)

            
            $DeploymentTarget.Servers.Values | ForEach-Object {
                $server = ConvertTo-ManagementServerObject -ManifestServerObject $_
                write-Xmlnode -XmlRoot $xmlRoot -ParentNode $deploymentTargetNode -value $server | Out-Null
            }

            $xmlRoot.Save($destinationFilePath)

        }

                   
    }
}

